/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package functionalEnrichment.semanticSimilarity;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.uncommons.maths.random.MersenneTwisterRNG;
import utils.FileUtils;
import utils.Handle;

/**
 *
 * @author jamie
 */
public class MakeGeneSetsForAnalysis {

    private File outputFolder = new File("/Users/jamie/Dropbox/monkeys/GO/semanticSimilarity/geneSets");
    private File uniprotLookupFile = new File("/Users/jamie/Dropbox/monkeys/biomart/gId_to_uniprotAccession.txt");
    private Handle handle = Handle.getConnectedHandle("monkeys");
    private HashMap<Integer, String> accessionMap = new HashMap<Integer, String>();
    private int randomLists = 1000;
    private HashMap<String, List<String>> deGenes = new HashMap<String, List<String>>();
    private MersenneTwisterRNG twister = new MersenneTwisterRNG();

    public MakeGeneSetsForAnalysis() {
        fillAccessionMap();
        System.out.println("accessionMap contains " + accessionMap.size() + " mappings");
        fillDeGenesList();

        for (int i = 1; i <= 15; i++) {
            try {
                makeOutputFile(i);
            } catch (IOException ex) {
                Logger.getLogger(MakeGeneSetsForAnalysis.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void fillAccessionMap() {
        BufferedReader reader = FileUtils.getBufferedReader(uniprotLookupFile);
        String line;
        try {
            while ((line = reader.readLine()) != null) {
//                System.out.println(line);
                String[] split = line.split("\t");
                if (split.length > 1) {
                    if (split[0].length() > 0 && split[1].length() > 0) {
                        int gId = Integer.parseInt(split[0]);
                        String accession = split[1];
                        accessionMap.put(gId, accession);
                    }
                }
            }

        } catch (IOException ex) {
            Logger.getLogger(MakeGeneSetsForAnalysis.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            reader.close();
        } catch (IOException ex) {
            Logger.getLogger(MakeGeneSetsForAnalysis.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void makeOutputFile(int clusterId) throws IOException {
        BufferedWriter writer = FileUtils.getBufferedWriter(new File(outputFolder, "lists_" + clusterId + ".txt"));
        HashMap<String, List<String>> accessions_cluster = getAccessions(clusterId);
        output(accessions_cluster, writer, "realCluster_" + clusterId);
        for (int i = 1; i <= randomLists; i++) {
            HashMap<String, List<String>> randomAccessions = getRandomAccessions(accessions_cluster);
            output(randomAccessions, writer, "randomCluster_" + i);
        }
        writer.close();
    }

    private HashMap<String, List<String>> getAccessions(int clusterId) {
        String sql = "select distinct t2.gId, t3.monkeyType, t3.cellType from probeIdLookup t2, clusterMembership t3 where  t2.probeId=t3.probeId and clusterId=" + clusterId;
        ResultSet rs = handle.runSQLquery(sql);
        HashMap<String, List<String>> accessions = new HashMap<String, List<String>>();
        try {
            while (rs.next()) {
                String source = rs.getString("t3.monkeyType") + rs.getString("t3.cellType");
                int gId = rs.getInt("gId");
                if (!accessions.containsKey(source)) {
                    accessions.put(source, new ArrayList<String>());
                }
                if (accessionMap.containsKey(gId)) {
                    accessions.get(source).add(accessionMap.get(gId));
                }
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(MakeGeneSetsForAnalysis.class.getName()).log(Level.SEVERE, null, ex);
        }
        return accessions;
    }

    private void output(HashMap<String, List<String>> accessions, BufferedWriter writer, String name) throws IOException {
        writer.append("#" + name+"\n");
        for (List<String> list : accessions.values()) {
            for (String accession : list) {
                writer.append(accession + "\n");
            }
        }
        writer.append("\n");
    }

    private HashMap<String, List<String>> getRandomAccessions(HashMap<String, List<String>> realData) {
        HashMap<String, List<String>> random = new HashMap<String, List<String>>();
        for (String source : realData.keySet()) {
            random.put(source, new ArrayList<String>());
            for (int i = 0; i < realData.get(source).size(); i++) {
                addRandomAccession(deGenes.get(source), random.get(source));
            }
        }
        return random;
    }

    private void fillDeGenesList() {
        String sql = "select distinct monkeyType, cellType, gId from differentialexpression where (timePoint=1 || timePoint=14 || timePoint=28 || timePoint=65) and pValue<0.1";
        ResultSet rs = handle.runSQLquery(sql);
        try {
            while (rs.next()) {
                String source = rs.getString("monkeyType") + rs.getString("cellType");
                int gId = rs.getInt("gId");
                if (!deGenes.containsKey(source)) {
                    deGenes.put(source, new ArrayList<String>());
                }
                if (accessionMap.containsKey(gId)) {
                    deGenes.get(source).add(accessionMap.get(gId));
                }
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(MakeGeneSetsForAnalysis.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void addRandomAccession(List<String> deGenes, List<String> randomSet) {
        int randomIndex = twister.nextInt(deGenes.size());
        if (!randomSet.contains(deGenes.get(randomIndex))) {
            randomSet.add(deGenes.get(randomIndex));
//            System.out.println("adding");
        } else {
            addRandomAccession(deGenes, randomSet);
//            System.out.println("failing to add "+deGenes.size()+", "+randomSet.size());
        }
    }
}
